package com.dnzx.security;

import nl.captcha.Captcha;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * <li>带验证码校验功能的用户名、密码认证过滤器</li>
 * <p>
 * 支持不输入验证码；支持验证码忽略大小写。
 * 
 * @author Steven
 * 
 */
public class ValidateCodeUsernamePasswordAuthenticationFilter extends
		UsernamePasswordAuthenticationFilter {
	/**
	 * 是否只允许post请求登陆
	 */
	private boolean postOnly;
    /**
     * session中验证码参数名
     */
	private String sessionValidateCodeName;
    /**
     * request请求中验证码参数名
     */
	private String requestValidateCodeName;
	/**
	 * 是否开启验证码验证
	 */
	private Boolean isEnableValidateCode;

	@Override
	public Authentication attemptAuthentication(HttpServletRequest request,
			HttpServletResponse response) throws AuthenticationException {
		if (this.postOnly && !"POST".equals(request.getMethod())) {
			throw new AuthenticationServiceException("");
		}

        //获取request请求中的用户名和密码
        String username = StringUtils.trim(obtainUsername(request));
        String password = obtainPassword(request);

		if (StringUtils.isBlank(username)) {
			throw new AuthenticationServiceException("登录帐号必须填写");
		}
		if (StringUtils.isBlank(password)) {
			throw new AuthenticationServiceException("登录密码必须填写");
		}
        //将用户名和密码保存到缓存中
        HttpSession session = request.getSession();
        session.setAttribute("username", username);
        session.setAttribute("password", password);
		UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
				username, password);
		setDetails(request, authRequest);
		//校验验证码是否正确
		checkValidateCode(request);
		//请求父类进行认证
		return this.getAuthenticationManager().authenticate(authRequest);
	}

	/**
	 * 
	 * <li>比较session中的验证码和用户输入的验证码是否相等</li>
	 * 
	 */
	protected void checkValidateCode(HttpServletRequest request) {
	    //无需验证码校验直接返回
		if (!isEnableValidateCode) {
			return;
		}
        String sessionValidateCode = obtainSessionValidateCode(request);
        String requestValidateCode = obtainRequestValidateCode(request);
		if (StringUtils.isEmpty(requestValidateCode)
				|| !sessionValidateCode.equalsIgnoreCase(requestValidateCode)) {
			throw new AuthenticationServiceException(
					messages.getMessage("validateCode.notEquals"));
		}
	}

    protected String obtainRequestValidateCode(HttpServletRequest request) {
		return request.getParameter(getRequestValidateCodeName());
	}

	protected String obtainSessionValidateCode(HttpServletRequest request) {
		Captcha obj = (Captcha) request.getSession().getAttribute(
				getSessionValidateCodeName());
		return null == obj ? "" : obj.getAnswer();
	}

	public String getSessionValidateCodeName() {
		return sessionValidateCodeName;
	}

	public void setSessionValidateCodeName(String sessionValidateCodeName) {
		this.sessionValidateCodeName = sessionValidateCodeName;
	}

    public String getRequestValidateCodeName() {
        return requestValidateCodeName;
    }

    public void setRequestValidateCodeName(String requestValidateCodeName) {
        this.requestValidateCodeName = requestValidateCodeName;
    }

    public Boolean getIsEnableValidateCode() {
		return isEnableValidateCode;
	}

	public void setIsEnableValidateCode(Boolean isEnableValidateCode) {
		this.isEnableValidateCode = isEnableValidateCode;
	}

}
